home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 41 / Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso / -seriously_amiga- / programming / other / scrollingtricks / source / scroller_xyunlimited2 / main.c < prev    next >
C/C++ Source or Header  |  1999-04-19  |  25KB  |  1,249 lines

  1. #include <exec/exec.h>
  2. #include <dos/dos.h>
  3. #include <intuition/intuition.h>
  4. #include <graphics/gfx.h>
  5. #include <hardware/custom.h>
  6. #include <hardware/dmabits.h>
  7.  
  8. #ifdef __MAXON__
  9. #include <pragma/exec_lib.h>
  10. #include <pragma/dos_lib.h>
  11. #include <pragma/graphics_lib.h>
  12. #include <pragma/intuition_lib.h>
  13. #else
  14. #include <proto/exec.h>
  15. #include <proto/dos.h>
  16. #include <proto/graphics.h>
  17. #include <proto/intuition.h>
  18. #endif
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22.  
  23. #include "hardware.h"
  24. #include "cop.h"
  25. #include "map.h"
  26.  
  27.  
  28. #define ARG_TEMPLATE "SPEED/S,NTSC/S,HOW/S,FMODE/N/K"
  29. #define ARG_SPEED 0
  30. #define ARG_NTSC  1
  31. #define ARG_HOW   2
  32. #define ARG_FMODE 3
  33. #define NUM_ARGS  4
  34.  
  35. #define MAPNAME        "maps/scroller.raw"
  36. #define BLOCKSNAME    "blocks/demoblocks.raw"
  37.  
  38. #define SCREENWIDTH  320
  39. #define SCREENHEIGHT 256
  40. #define EXTRAWIDTH  64
  41. #define EXTRAHEIGHT 32
  42. #define SCREENBYTESPERROW (SCREENWIDTH / 8)
  43.  
  44. #define BITMAPWIDTH (SCREENWIDTH + EXTRAWIDTH)
  45. #define BITMAPBYTESPERROW (BITMAPWIDTH / 8)
  46. #define BITMAPHEIGHT (SCREENHEIGHT + EXTRAHEIGHT)
  47.  
  48. #define BLOCKSWIDTH 320
  49. #define BLOCKSHEIGHT 200
  50. #define BLOCKSDEPTH 4
  51. #define BLOCKSCOLORS (1L << BLOCKSDEPTH)
  52. #define BLOCKWIDTH 16
  53. #define BLOCKHEIGHT 16
  54. #define BLOCKSBYTESPERROW (BLOCKSWIDTH / 8)
  55. #define BLOCKSPERROW (BLOCKSWIDTH / BLOCKWIDTH)
  56.  
  57. #define NUMSTEPS_X BLOCKWIDTH
  58. #define NUMSTEPS_Y BLOCKHEIGHT
  59.  
  60. #define BITMAPBLOCKSPERROW (BITMAPWIDTH / BLOCKWIDTH)
  61. #define BITMAPBLOCKSPERCOL (BITMAPHEIGHT / BLOCKHEIGHT)
  62.  
  63. #define VISIBLEBLOCKSX (SCREENWIDTH / BLOCKWIDTH)
  64. #define VISIBLEBLOCKSY (SCREENHEIGHT / BLOCKHEIGHT)
  65.  
  66. #define BITMAPPLANELINES (BITMAPHEIGHT * BLOCKSDEPTH)
  67. #define BLOCKPLANELINES  (BLOCKHEIGHT * BLOCKSDEPTH)
  68.  
  69. #define PLANEPIXELBITMAPWIDTH (BITMAPWIDTH * BLOCKSDEPTH)
  70.  
  71. #define DIWSTART 0x2981
  72. #define DIWSTOP  0x29C1
  73.  
  74. #define PALSIZE (BLOCKSCOLORS * 2)
  75. #define BLOCKSFILESIZE (BLOCKSWIDTH * BLOCKSHEIGHT * BLOCKSPLANES / 8 + PALSIZE)
  76.  
  77. #define DIRECTION_IGNORE 0
  78. #define DIRECTION_LEFT   1
  79. #define DIRECTION_RIGHT  2
  80.  
  81. #define UP 1
  82. #define DOWN 2
  83.  
  84. // calculate how many times (steps) y-scrolling needs to
  85. // blit two blocks instead of one block to make sure a
  86. // complete row is blitted after 16 pixels of y-scrolling
  87. //
  88. // x * 2 + (16 - x) = BITMAPBLOCKSPERROW
  89. // 2x + 16 - x = BITMAPBLOCKSPERROW
  90. // x = BITMAPBLOCKSPERROW - 16
  91.  
  92. #define TWOBLOCKS (BITMAPBLOCKSPERROW - NUMSTEPS_Y)
  93. #define TWOBLOCKSTEP TWOBLOCKS
  94.  
  95. struct IntuitionBase *IntuitionBase;
  96. struct GfxBase *GfxBase;
  97. struct Screen *scr;
  98. struct RastPort *ScreenRastPort;
  99. struct BitMap *BlocksBitmap,*ScreenBitmap;
  100. struct RawMap *Map;
  101. UBYTE     *frontbuffer,*blocksbuffer;
  102.  
  103. WORD    mapposx,mapposy,videoposx,videoposy,block_videoposy;
  104. WORD    mapblockx,mapblocky,stepx,stepy;
  105. WORD    bitmapheight,bitplanemodulo;
  106.  
  107. WORD    *savewordpointer;
  108. WORD    saveword;
  109. BYTE    previous_xdirection;
  110.  
  111. LONG    mapwidth,mapheight;
  112. UBYTE *mapdata;
  113.  
  114. UWORD    colors[BLOCKSCOLORS];
  115.  
  116. LONG    Args[NUM_ARGS];
  117.  
  118. BOOL    option_ntsc,option_how,option_speed;
  119. WORD    option_fetchmode;
  120.  
  121. BPTR    MyHandle;
  122. char    s[256];
  123.  
  124. #if EXTRAWIDTH == 32
  125.  
  126.     // bitmap width aligned to 32 Pixels
  127.     #define MAX_FETCHMODE 2
  128.     #define MAX_FETCHMODE_S "2"
  129.  
  130. #elif EXTRAWIDTH == 64
  131.  
  132.     // bitmap width aligned to 64 Pixels
  133.     #define MAX_FETCHMODE 3
  134.     #define MAX_FETCHMODE_S "3"
  135.  
  136. #else
  137.  
  138.     // bad extrawidth
  139.     #error "EXTRAWIDTH must be either 32 or 64"
  140.  
  141. #endif
  142.  
  143. struct FetchInfo
  144. {
  145.     WORD    ddfstart;
  146.     WORD    ddfstop;
  147.     WORD    modulooffset;
  148.     WORD    bitmapoffset;
  149.     WORD    scrollpixels;
  150. } fetchinfo [] =
  151. {
  152.     {0x30,0xD0,2,0,16},    /* normal         */
  153.     {0x28,0xC8,4,16,32},    /* BPL32          */
  154.     {0x28,0xC8,4,16,32},    /* BPAGEM         */
  155.     {0x18,0xB8,8,48,64}    /* BPL32 + BPAGEM */
  156. };
  157.  
  158. /********************* MACROS ***********************/
  159.  
  160. #define ROUND2BLOCKWIDTH(x)  ((x) & ~(BLOCKWIDTH - 1))
  161. #define ROUND2BLOCKHEIGHT(x) ((x) & ~(BLOCKHEIGHT - 1))
  162.  
  163. /************* SETUP/CLEANUP ROUTINES ***************/
  164.  
  165. static void Cleanup (char *msg)
  166. {
  167.     WORD rc;
  168.     
  169.     if (msg)
  170.     {
  171.         printf("Error: %s\n",msg);
  172.         rc = RETURN_WARN;
  173.     } else {
  174.         rc = RETURN_OK;
  175.     }
  176.  
  177.     if (scr) CloseScreen(scr);
  178.  
  179.     if (ScreenBitmap)
  180.     {
  181.         WaitBlit();
  182.         FreeBitMap(ScreenBitmap);
  183.     }
  184.  
  185.     if (BlocksBitmap)
  186.     {
  187.         WaitBlit();
  188.         FreeBitMap(BlocksBitmap);
  189.     }
  190.  
  191.     if (Map) FreeVec(Map);
  192.     if (MyHandle) Close(MyHandle);
  193.  
  194.     if (GfxBase) CloseLibrary((struct Library *)GfxBase);
  195.     if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
  196.  
  197.     exit(rc);
  198. }
  199.  
  200. static void OpenLibs(void)
  201. {
  202.     if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",39)))
  203.     {
  204.         Cleanup("Can't open intuition.library V39!");
  205.     }
  206.     
  207.     if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",39)))
  208.     {
  209.         Cleanup("Can't open graphics.library V39!");
  210.     }
  211. }
  212.  
  213. static void GetArguments(void)
  214. {
  215.     struct RDArgs *MyArgs;
  216.  
  217.     if (!(MyArgs = ReadArgs(ARG_TEMPLATE,Args,0)))
  218.     {
  219.         Fault(IoErr(),0,s,255);
  220.         Cleanup(s);
  221.     }
  222.  
  223.     if (Args[ARG_SPEED]) option_speed = TRUE;
  224.     if (Args[ARG_NTSC]) option_ntsc = TRUE;
  225.     if (Args[ARG_HOW])
  226.     {
  227.         option_how = TRUE;
  228.         option_speed = FALSE;
  229.     }
  230.  
  231.     if (Args[ARG_FMODE])
  232.     {
  233.         option_fetchmode = *(LONG *)Args[ARG_FMODE];
  234.     }
  235.  
  236.     FreeArgs(MyArgs);
  237.     
  238.     if (option_fetchmode < 0 || option_fetchmode > MAX_FETCHMODE)
  239.     {
  240.         Cleanup("Invalid fetch mode. Must be 0 .. " MAX_FETCHMODE_S "!");
  241.     }
  242.  
  243. }
  244.  
  245. static void OpenMap(void)
  246. {
  247.     LONG l;
  248.  
  249.     if (!(MyHandle = Open(MAPNAME,MODE_OLDFILE)))
  250.     {
  251.         Fault(IoErr(),0,s,255);
  252.         Cleanup(s);
  253.     }
  254.     
  255.     Seek(MyHandle,0,OFFSET_END);
  256.     l = Seek(MyHandle,0,OFFSET_BEGINNING);
  257.  
  258.     if (!(Map = AllocVec(l,MEMF_PUBLIC)))
  259.     {
  260.         Cleanup("Out of memory!");
  261.     }
  262.     
  263.     if (Read(MyHandle,Map,l) != l)
  264.     {
  265.         Fault(IoErr(),0,s,255);
  266.         Cleanup(s);
  267.     }
  268.     
  269.     Close(MyHandle);MyHandle = 0;
  270.     
  271.     mapdata = Map->data;
  272.     mapwidth = Map->mapwidth;
  273.     mapheight = Map->mapheight;
  274. }
  275.  
  276. static void OpenBlocks(void)
  277. {
  278.     LONG l;
  279.  
  280.     if (!(BlocksBitmap = AllocBitMap(BLOCKSWIDTH,
  281.                                                BLOCKSHEIGHT,
  282.                                                BLOCKSDEPTH,
  283.                                                BMF_STANDARD | BMF_INTERLEAVED,
  284.                                                0)))
  285.     {
  286.         Cleanup("Can't alloc blocks bitmap!");
  287.     }
  288.     
  289.     if (!(MyHandle = Open(BLOCKSNAME,MODE_OLDFILE)))
  290.     {
  291.         Fault(IoErr(),0,s,255);
  292.         Cleanup(s);
  293.     }
  294.     
  295.     if (Read(MyHandle,colors,PALSIZE) != PALSIZE)
  296.     {
  297.         Fault(IoErr(),0,s,255);
  298.         Cleanup(s);
  299.     }
  300.     
  301.     l = BLOCKSWIDTH * BLOCKSHEIGHT * BLOCKSDEPTH / 8;
  302.     
  303.     if (Read(MyHandle,BlocksBitmap->Planes[0],l) != l)
  304.     {
  305.         Fault(IoErr(),0,s,255);
  306.         Cleanup(s);
  307.     }
  308.     
  309.     Close(MyHandle);MyHandle = 0;
  310.     
  311.     blocksbuffer = BlocksBitmap->Planes[0];
  312. }
  313.  
  314. static void OpenDisplay(void)
  315. {    
  316.     struct DimensionInfo diminfo;
  317.     DisplayInfoHandle        dih;
  318.     ULONG                        modeid;
  319.     LONG                        l;
  320.     
  321.     bitmapheight = BITMAPHEIGHT + 3;
  322.  
  323.     if (!(ScreenBitmap = AllocBitMap(BITMAPWIDTH,bitmapheight,BLOCKSDEPTH,BMF_STANDARD | BMF_INTERLEAVED | BMF_CLEAR,0)))
  324.     {
  325.         Cleanup("Can't alloc screen bitmap!");
  326.     }
  327.  
  328.     frontbuffer = ScreenBitmap->Planes[0];
  329.     frontbuffer += (fetchinfo[option_fetchmode].bitmapoffset / 8);
  330.  
  331.     if (!(TypeOfMem(ScreenBitmap->Planes[0]) & MEMF_CHIP))
  332.     {
  333.         Cleanup("Screen bitmap is not in CHIP RAM!?? If you have a gfx card try disabling \"planes to fast\" or similiar options in your RTG system!");
  334.     }
  335.  
  336.     l = GetBitMapAttr(ScreenBitmap,BMA_FLAGS);
  337.     
  338.     if (!(GetBitMapAttr(ScreenBitmap,BMA_FLAGS) & BMF_INTERLEAVED))
  339.     {
  340.         Cleanup("Screen bitmap is not in interleaved format!??");
  341.     }
  342.     
  343.     if (option_how)
  344.     {
  345.         modeid = INVALID_ID;
  346.  
  347.         if ((dih = FindDisplayInfo(VGAPRODUCT_KEY)))
  348.         {
  349.             if (GetDisplayInfoData(dih,(APTR)&diminfo,sizeof(diminfo),DTAG_DIMS,0))
  350.             {
  351.                 if (diminfo.MaxDepth >= BLOCKSDEPTH) modeid = VGAPRODUCT_KEY;
  352.             }
  353.         }
  354.         if (modeid == INVALID_ID)
  355.         {
  356.             if (option_ntsc)
  357.             {
  358.                 modeid = NTSC_MONITOR_ID | HIRESLACE_KEY;
  359.             } else {
  360.                 modeid = PAL_MONITOR_ID | HIRESLACE_KEY;
  361.             }
  362.         }
  363.     } else {
  364.         if (option_ntsc)
  365.         {
  366.             modeid = NTSC_MONITOR_ID;
  367.         } else {
  368.             modeid = PAL_MONITOR_ID;
  369.         }
  370.     }
  371.  
  372.     if (!(scr = OpenScreenTags(0,SA_Width,BITMAPWIDTH,
  373.                                           SA_Height,bitmapheight,
  374.                                           SA_Depth,BLOCKSDEPTH,
  375.                                           SA_DisplayID,modeid,
  376.                                           SA_BitMap,ScreenBitmap,
  377.                                           option_how ? SA_Overscan : TAG_IGNORE,OSCAN_TEXT,
  378.                                           option_how ? SA_AutoScroll : TAG_IGNORE,TRUE,
  379.                                           SA_Quiet,TRUE,
  380.                                           TAG_DONE)))
  381.     {
  382.         Cleanup("Can't open screen!");
  383.     }
  384.  
  385.     if (scr->RastPort.BitMap->Planes[0] != ScreenBitmap->Planes[0])
  386.     {
  387.         Cleanup("Screen was not created with the custom bitmap I supplied!??");
  388.     }
  389.     
  390.     ScreenRastPort = &scr->RastPort;
  391.     
  392.     LoadRGB4(&scr->ViewPort,colors,BLOCKSCOLORS);
  393. }
  394.  
  395. static void InitCopperlist(void)
  396. {
  397.     WORD    *wp;
  398.     ULONG    plane,plane2;
  399.     LONG    l;
  400.  
  401.     WaitVBL();
  402.  
  403.     custom->dmacon = 0x7FFF;
  404.     custom->beamcon0 = option_ntsc ? 0 : DISPLAYPAL;
  405.  
  406.     CopFETCHMODE[1] = option_fetchmode;
  407.     
  408.     // bitplane control registers
  409.  
  410.     CopBPLCON0[1] = ((BLOCKSDEPTH * BPL0_BPU0_F) & BPL0_BPUMASK) +
  411.                          ((BLOCKSDEPTH / 8) * BPL0_BPU3_F) +
  412.                          BPL0_COLOR_F +
  413.                          (option_speed ? 0 : BPL0_USEBPLCON3_F);
  414.  
  415.     CopBPLCON1[1] = 0;
  416.  
  417.     CopBPLCON3[1] = BPLCON3_BRDNBLNK;
  418.  
  419.     // bitplane modulos
  420.  
  421.     l = BITMAPBYTESPERROW * BLOCKSDEPTH -
  422.          SCREENBYTESPERROW - fetchinfo[option_fetchmode].modulooffset;
  423.  
  424.     CopBPLMODA[1] = l;
  425.     CopBPLMODB[1] = l;
  426.     
  427.     CopVIDEOSPLITRESETMODULO[1] = l;
  428.     CopVIDEOSPLITRESETMODULO[3] = l;
  429.  
  430.     bitplanemodulo = l;
  431.  
  432.     // display window start/stop
  433.     
  434.     CopDIWSTART[1] = DIWSTART;
  435.     CopDIWSTOP[1] = DIWSTOP;
  436.     
  437.     // display data fetch start/stop
  438.     
  439.     CopDDFSTART[1] = fetchinfo[option_fetchmode].ddfstart;
  440.     CopDDFSTOP[1]  = fetchinfo[option_fetchmode].ddfstop;
  441.     
  442.     // plane pointers
  443.  
  444.     wp = CopPLANE1H;
  445.  
  446.     for(l = 0;l < BLOCKSDEPTH;l++)
  447.     {
  448.         plane = (ULONG)ScreenBitmap->Planes[l];
  449.         
  450.         wp[1] = plane >> 16;
  451.         wp[3] = plane & 0xFFFF;
  452.  
  453.         wp += 4;
  454.     }
  455.  
  456.     // setup modulo trick
  457.     
  458.     plane = (ULONG)ScreenBitmap->Planes[0];
  459.  
  460.     plane2 = plane +
  461.                 (BITMAPHEIGHT - 1) * BITMAPBYTESPERROW * BLOCKSDEPTH +
  462.                 SCREENBYTESPERROW +
  463.                 fetchinfo[option_fetchmode].modulooffset;
  464.  
  465.     l = (plane - plane2) & 0xFFFF;
  466.  
  467.     CopVIDEOSPLITMODULO[1] = l;
  468.     CopVIDEOSPLITMODULO[3] = l;
  469.     
  470.     CopVIDEOSPLITMODULO[1] = l;
  471.     CopVIDEOSPLITMODULO[3] = l;
  472.  
  473.     /**/
  474.     
  475.     custom->intena = 0x7FFF;
  476.     
  477.     custom->dmacon = DMAF_SETCLR | DMAF_BLITTER | DMAF_COPPER | DMAF_RASTER | DMAF_MASTER;
  478.  
  479.     custom->cop2lc = (ULONG)CopperList;    
  480. };
  481.  
  482. /******************* SCROLLING **********************/
  483.  
  484. static void DrawBlock(LONG x,LONG y,LONG mapx,LONG mapy)
  485. {
  486.     UBYTE block;
  487.  
  488.     // x = in pixels
  489.     // y = in "planelines" (1 realline = BLOCKSDEPTH planelines)
  490.  
  491.     x = (x / 8) & 0xFFFE;
  492.     
  493.     block = mapdata[mapy * mapwidth + mapx];
  494.  
  495.     mapx = (block % BLOCKSPERROW) * (BLOCKWIDTH / 8);
  496.     mapy = (block / BLOCKSPERROW) * (BLOCKPLANELINES * BLOCKSBYTESPERROW);
  497.     
  498.     if (option_how) OwnBlitter();
  499.  
  500.     if (y + BLOCKPLANELINES <= BITMAPPLANELINES)
  501.     {
  502.         // blit does not cross bitmap's bottom boundary
  503.         
  504.         HardWaitBlit();
  505.         
  506.         custom->bltcon0 = 0x9F0;    // use A and D. Op: D = A
  507.         custom->bltcon1 = 0;
  508.         custom->bltafwm = 0xFFFF;
  509.         custom->bltalwm = 0xFFFF;
  510.         custom->bltamod = BLOCKSBYTESPERROW - (BLOCKWIDTH / 8);
  511.         custom->bltdmod = BITMAPBYTESPERROW - (BLOCKWIDTH / 8);
  512.         custom->bltapt  = blocksbuffer + mapy + mapx;
  513.         custom->bltdpt     = frontbuffer + y * BITMAPBYTESPERROW + x;
  514.         
  515.         custom->bltsize = BLOCKPLANELINES * 64 + (BLOCKWIDTH / 16);
  516.     } else {
  517.         // blit does cross bitmap's bottom boundary
  518.         // --> need to split blit = do two blit operations
  519.         
  520.         HardWaitBlit();
  521.         
  522.         custom->bltcon0 = 0x9F0;    // use A and D. Op: D = A
  523.         custom->bltcon1 = 0;
  524.         custom->bltafwm = 0xFFFF;
  525.         custom->bltalwm = 0xFFFF;
  526.         custom->bltamod = BLOCKSBYTESPERROW - (BLOCKWIDTH / 8);
  527.         custom->bltdmod = BITMAPBYTESPERROW - (BLOCKWIDTH / 8);
  528.         custom->bltapt  = blocksbuffer + mapy + mapx;
  529.         custom->bltdpt     = frontbuffer + y * BITMAPBYTESPERROW + x;
  530.         
  531.         y = BITMAPPLANELINES - y;
  532.         custom->bltsize = y * 64 + (BLOCKWIDTH / 16);
  533.         
  534.         HardWaitBlit();
  535.  
  536.         custom->bltdpt  = frontbuffer + x;
  537.         custom->bltsize = (BLOCKPLANELINES - y)  * 64 + (BLOCKWIDTH / 16);
  538.  
  539.     }
  540.  
  541.     if (option_how) DisownBlitter();
  542. }
  543.  
  544. static void FillScreen(void)
  545. {
  546.     WORD a,b,x,y;
  547.     
  548.     for (b = 0;b < BITMAPBLOCKSPERCOL;b++)
  549.     {
  550.         for (a = 0;a < BITMAPBLOCKSPERROW;a++)
  551.         {
  552.             x = a * BLOCKWIDTH;
  553.             y = b * BLOCKPLANELINES;
  554.  
  555.             DrawBlock(x,y,a,b);
  556.         }
  557.     }
  558. }
  559.  
  560. static void BlitExtraLine(WORD dest)
  561. {
  562.     UBYTE *a,*b;
  563.  
  564.     a = frontbuffer;
  565.     b = frontbuffer + BITMAPPLANELINES * BITMAPBYTESPERROW;
  566.     
  567.     HardWaitBlit();
  568.         
  569.     custom->bltcon0 = 0x9F0;
  570.     custom->bltcon1 = 0;
  571.     custom->bltafwm = 0xFFFF;
  572.     custom->bltalwm = 0xFFFF;
  573.     custom->bltamod = 0;
  574.     custom->bltdmod = 0;
  575.     custom->bltapt  = (dest == UP) ? b : a;
  576.     custom->bltdpt  = (dest == UP) ? a : b;
  577.  
  578.     custom->bltsize = 1 * BLOCKSDEPTH * 64 + (BITMAPBYTESPERROW / 2);
  579. }
  580.  
  581. static void ScrollUp(void)
  582. {
  583.     WORD mapx,mapy,x,y;
  584.  
  585.     if (mapposy < 1) return;
  586.  
  587.     mapposy--;
  588.     mapblocky = mapposy / BLOCKHEIGHT;
  589.     stepy = mapposy & (NUMSTEPS_Y - 1);
  590.     
  591.     videoposy--;
  592.     if (videoposy < 0) videoposy += BITMAPHEIGHT;
  593.     if (stepy == (NUMSTEPS_Y - 1))
  594.     {
  595.         block_videoposy -= BLOCKHEIGHT;
  596.         if (block_videoposy < 0) block_videoposy += BITMAPHEIGHT;
  597.     }
  598.     
  599.     if (stepy == (NUMSTEPS_Y - 1))
  600.     {
  601.         // a complete row is filled up
  602.         // : the next fill up row will be BLOCKHEIGHT (16)
  603.         // pixels at the top, so we have to adjust
  604.         // the fillup column (for x scrolling), but
  605.         // only if the fillup column (x) contains some
  606.         // fill up blocks
  607.         
  608.         if (stepx)
  609.         {
  610.             // step 1: blit the 1st block in the fillup
  611.             //         col (x). There can only be 0 or
  612.             //         [2 or more] fill up blocks in the
  613.             //         actual implementation, so we do
  614.             //         not need to check previous_xdirection
  615.             //         for this blit
  616.             
  617.             mapx = mapblockx + BITMAPBLOCKSPERROW;
  618.             mapy = mapblocky + 1;
  619.             
  620.             x = ROUND2BLOCKWIDTH(videoposx);
  621.             y = (block_videoposy + BLOCKHEIGHT) % BITMAPHEIGHT;
  622.             y *= BLOCKSDEPTH;
  623.  
  624.             DrawBlock(x + BITMAPWIDTH,y,mapx,mapy);
  625.             
  626.             // step 2: remove the (former) bottommost fill up
  627.             // block
  628.             
  629.             if (previous_xdirection == DIRECTION_RIGHT)
  630.             {
  631.                 *savewordpointer = saveword;
  632.             }
  633.             
  634.             mapy = stepx + 2;
  635.  
  636.             // we blit a 'left' block
  637.  
  638.             y = (block_videoposy + (mapy * BLOCKHEIGHT)) % BITMAPHEIGHT;
  639.             y *= BLOCKSDEPTH;
  640.             
  641.             savewordpointer = (WORD *)(frontbuffer + (y * BITMAPBYTESPERROW) + (x / 8));
  642.             saveword = *savewordpointer;
  643.  
  644.             mapx -= BITMAPBLOCKSPERROW;
  645.             mapy += mapblocky;
  646.  
  647.             DrawBlock(x,y,mapx,mapy);
  648.             
  649.             previous_xdirection = DIRECTION_LEFT;
  650.  
  651.         } /* if (stepx) */
  652.         
  653.     } /* if (stepy == NUMSTEPS_Y - 1) */
  654.  
  655.  
  656.     mapx = stepy;
  657.     mapy = mapblocky;
  658.     
  659.     y = block_videoposy * BLOCKSDEPTH;
  660.  
  661.    if (mapx >= TWOBLOCKSTEP)
  662.    {
  663.        // blit only one block
  664.        
  665.        mapx += TWOBLOCKSTEP;
  666.  
  667.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  668.  
  669.        mapx += mapblockx;
  670.  
  671.        DrawBlock(x,y,mapx,mapy);
  672.        
  673.    } else {
  674.        // blit two blocks
  675.        
  676.        mapx *= 2;
  677.  
  678.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  679.  
  680.         mapx += mapblockx;
  681.  
  682.        DrawBlock(x,y,mapx,mapy);
  683.        
  684.        x += BLOCKWIDTH;
  685.  
  686.        DrawBlock(x,y,mapx + 1,mapy);
  687.        
  688.    }
  689. }
  690.  
  691. static void ScrollDown(void)
  692. {
  693.     WORD mapx,mapy,x,y,y2;
  694.  
  695.     if (mapposy >= (mapheight * BLOCKHEIGHT - SCREENHEIGHT - BLOCKHEIGHT)) return;
  696.     
  697.     mapx = stepy;
  698.     mapy = mapblocky + BITMAPBLOCKSPERCOL;
  699.     
  700.     y = block_videoposy * BLOCKSDEPTH;
  701.  
  702.    if (mapx >= TWOBLOCKSTEP)
  703.    {
  704.        // blit only one block
  705.        
  706.        mapx += TWOBLOCKSTEP;
  707.  
  708.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  709.  
  710.        mapx += mapblockx;
  711.  
  712.        DrawBlock(x,y,mapx,mapy);
  713.        
  714.    } else {
  715.        // blit two blocks
  716.        
  717.        mapx *= 2;
  718.  
  719.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  720.  
  721.        mapx += mapblockx;
  722.        
  723.        DrawBlock(x,y,mapx,mapy);
  724.        
  725.        x += BLOCKWIDTH;
  726.  
  727.        DrawBlock(x,y,mapx + 1,mapy);
  728.    }
  729.  
  730.     mapposy++;
  731.     mapblocky = mapposy / BLOCKHEIGHT;
  732.     stepy = mapposy & (NUMSTEPS_Y - 1);
  733.     
  734.     videoposy++;
  735.     if (videoposy >= BITMAPHEIGHT) videoposy -= BITMAPHEIGHT;
  736.     
  737.     if (!stepy)
  738.     {
  739.         block_videoposy += BLOCKHEIGHT;
  740.         if (block_videoposy >= BITMAPHEIGHT) block_videoposy -= BITMAPHEIGHT;
  741.     }
  742.  
  743.     if (stepy == 0)
  744.     {
  745.         // a complete row is filled up
  746.         // : the next fill up row will be BLOCKHEIGHT (16)
  747.         // pixels at the bottom, so we have to adjust
  748.         // the fillup column (for x scrolling), but
  749.         // only if the fillup column (x) contains some
  750.         // fill up blocks
  751.         
  752.         if (stepx)
  753.         {
  754.             // step 1: blit the 1st block in the fillup
  755.             //         row (y) because this block must
  756.             //         not be part of the fillup col (x)
  757.             //         instead it is for exclusive use
  758.             //         by the fillup row
  759.             
  760.             mapx = mapblockx;
  761.             mapy = mapblocky;
  762.             
  763.             x = ROUND2BLOCKWIDTH(videoposx);
  764.             y = block_videoposy * BLOCKSDEPTH;
  765.             
  766.             DrawBlock(x,y,mapx,mapy);
  767.             
  768.             // step 2: blit the (new) bottommost fill up
  769.             // block
  770.             
  771.             if (previous_xdirection == DIRECTION_LEFT)
  772.             {
  773.                 *savewordpointer = saveword;
  774.             }
  775.             
  776.             mapy = stepx + 1;
  777.  
  778.             // we blit a 'right-block'
  779.  
  780.             x += BITMAPWIDTH;
  781.  
  782.             y = (block_videoposy + (mapy * BLOCKHEIGHT)) % BITMAPHEIGHT;
  783.             y *= BLOCKSDEPTH;
  784.  
  785.             y2 = (y + BLOCKPLANELINES - 1) % BITMAPPLANELINES;
  786.             
  787.             savewordpointer = (WORD *)(frontbuffer + (y2 * BITMAPBYTESPERROW) + (x / 8));
  788.             saveword = *savewordpointer;
  789.  
  790.             mapx += BITMAPBLOCKSPERROW;
  791.             mapy += mapblocky;
  792.  
  793.             DrawBlock(x,y,mapx,mapy);
  794.             
  795.             previous_xdirection = DIRECTION_RIGHT;
  796.         } /* if (stepx) */
  797.         
  798.     } /* if (stepy == 0) */
  799.     
  800.  
  801. }
  802.  
  803. static void ScrollLeft(void)
  804. {
  805.     WORD mapx,mapy,x,y;
  806.     
  807.     if (mapposx < 1) return;
  808.     
  809.     mapposx--;
  810.     mapblockx = mapposx / BLOCKWIDTH;
  811.     stepx = mapposx & (NUMSTEPS_X - 1);
  812.  
  813.     videoposx--;
  814.     if (videoposx < 0)
  815.     {
  816.         BlitExtraLine(DOWN);
  817.  
  818.         videoposx = PLANEPIXELBITMAPWIDTH - 1;
  819.  
  820.         videoposy--;
  821.         if (videoposy < 0) videoposy = BITMAPHEIGHT - 1;
  822.  
  823.         block_videoposy--;
  824.         if (block_videoposy < 0) block_videoposy = BITMAPHEIGHT - 1;
  825.     }
  826.     
  827.     //
  828.  
  829.     if (stepx == (NUMSTEPS_X - 1))
  830.     {
  831.         // a complete column is filled up
  832.         // : the next fill up column will be BLOCKWIDTH (16)
  833.         // pixels at the left, so we have to adjust
  834.         // the fillup row (for y scrolling)
  835.         
  836.         // step 1: blit the block which came in at
  837.         //         the left side and which might or
  838.         //         might not be a fill up block
  839.         
  840.         mapx = mapblockx;
  841.         mapy = mapblocky;
  842.  
  843.         if (stepy)
  844.         {
  845.             // there is a fill up block
  846.             // so block which comes in left is
  847.             // a fillup block
  848.             
  849.             mapy += BITMAPBLOCKSPERCOL;
  850.         }
  851.  
  852.         x = ROUND2BLOCKWIDTH(videoposx);
  853.         y = block_videoposy * BLOCKSDEPTH;
  854.         
  855.         DrawBlock(x,y,mapx,mapy);
  856.         
  857.         // step 2: remove the (former) rightmost fillup-block
  858.         
  859.         mapx = stepy;
  860.         if (mapx)
  861.         {
  862.             // there is a fill up block;
  863.             
  864.             if (mapx >= TWOBLOCKSTEP)
  865.             {
  866.                 mapx += TWOBLOCKSTEP;
  867.             } else {
  868.                 mapx *= 2;
  869.             }
  870.                         
  871.             x = ROUND2BLOCKWIDTH(videoposx) + (mapx * BLOCKWIDTH);
  872.             y = block_videoposy * BLOCKSDEPTH;
  873.             
  874.             mapx += mapblockx;
  875.             mapy -= BITMAPBLOCKSPERCOL;
  876.             DrawBlock(x,y,mapx,mapy);
  877.         }
  878.  
  879.     }
  880.  
  881.  
  882.     mapx = mapblockx;
  883.     mapy = stepx + 1;
  884.  
  885.     x = ROUND2BLOCKWIDTH(videoposx);
  886.     
  887.     if (previous_xdirection == DIRECTION_RIGHT)
  888.     {
  889.         HardWaitBlit();
  890.         *savewordpointer = saveword;
  891.     }
  892.  
  893.     if (mapy == 1)
  894.     {
  895.         // blit two blocks
  896.  
  897.         mapy += mapblocky;
  898.         
  899.         y = (block_videoposy + (1 * BLOCKHEIGHT)) % BITMAPHEIGHT;
  900.         y *= BLOCKSDEPTH;
  901.  
  902.         savewordpointer = (WORD *)(frontbuffer + (y * BITMAPBYTESPERROW) + (x / 8));
  903.         saveword = *savewordpointer;
  904.         
  905.         DrawBlock(x,y,mapx,mapy);
  906.         
  907.         y = (y + BLOCKPLANELINES) % BITMAPPLANELINES;
  908.  
  909.         DrawBlock(x,y,mapx,mapy + 1);
  910.  
  911.     } else {
  912.         // blit one block
  913.  
  914.         mapy ++;
  915.         
  916.         y = (block_videoposy + (mapy * BLOCKHEIGHT)) % BITMAPHEIGHT;
  917.         y *= BLOCKSDEPTH;
  918.  
  919.         mapy += mapblocky;
  920.  
  921.         savewordpointer = (WORD *)(frontbuffer + (y * BITMAPBYTESPERROW) + (x / 8));
  922.         saveword = *savewordpointer;
  923.  
  924.         DrawBlock(x,y,mapx,mapy);
  925.     }
  926.     
  927.     if (stepx)
  928.     {
  929.         previous_xdirection = DIRECTION_LEFT;
  930.     } else {
  931.         previous_xdirection = DIRECTION_IGNORE;
  932.     }
  933. }
  934.  
  935. static void ScrollRight(void)
  936. {
  937.     WORD mapx,mapy,x,y,y2;
  938.     
  939.     if (mapposx >= (mapwidth * BLOCKWIDTH - SCREENWIDTH - BLOCKWIDTH)) return;
  940.  
  941.     mapx = mapblockx + BITMAPBLOCKSPERROW;
  942.     mapy = stepx + 1;
  943.  
  944.     x = ROUND2BLOCKWIDTH(videoposx);
  945.     
  946.     if (previous_xdirection == DIRECTION_LEFT)
  947.     {
  948.         HardWaitBlit();
  949.         *savewordpointer = saveword;
  950.     }
  951.  
  952.     if (mapy == 1)
  953.     {
  954.         // blit two blocks
  955.  
  956.         mapy += mapblocky;
  957.         
  958.         y = (block_videoposy + (1 * BLOCKHEIGHT)) % BITMAPHEIGHT;
  959.         y *= BLOCKSDEPTH;
  960.  
  961.         DrawBlock(x + BITMAPWIDTH,y,mapx,mapy);
  962.         
  963.         y = (y + BLOCKPLANELINES) % BITMAPPLANELINES;
  964.         y2 = (y + BLOCKPLANELINES - 1) % BITMAPPLANELINES;
  965.         
  966.         savewordpointer = (WORD *)(frontbuffer + (y2 * BITMAPBYTESPERROW) + ((x + BITMAPWIDTH) / 8));
  967.         saveword = *savewordpointer;
  968.  
  969.         DrawBlock(x + BITMAPWIDTH,y,mapx,mapy + 1);
  970.  
  971.     } else {
  972.         // blit one block
  973.  
  974.         mapy ++;
  975.         
  976.         y = (block_videoposy + (mapy * BLOCKHEIGHT)) % BITMAPHEIGHT;
  977.         y *= BLOCKSDEPTH;
  978.         y2 = (y + BLOCKPLANELINES - 1) % BITMAPPLANELINES;
  979.         
  980.         mapy += mapblocky;
  981.  
  982.         savewordpointer = (WORD *)(frontbuffer + (y2 * BITMAPBYTESPERROW) + ((x + BITMAPWIDTH) / 8));
  983.         saveword = *savewordpointer;
  984.  
  985.         DrawBlock(x + BITMAPWIDTH,y,mapx,mapy);
  986.     }
  987.     
  988.     //
  989.     
  990.     mapposx++;
  991.     mapblockx = mapposx / BLOCKWIDTH;
  992.     stepx = mapposx & (NUMSTEPS_X - 1);
  993.  
  994.     videoposx++;
  995.     if (videoposx == PLANEPIXELBITMAPWIDTH)
  996.     {
  997.         BlitExtraLine(UP);
  998.  
  999.         videoposx = 0;
  1000.  
  1001.         videoposy++;
  1002.         if (videoposy == BITMAPHEIGHT) videoposy = 0;
  1003.  
  1004.         block_videoposy++;
  1005.         if (block_videoposy == BITMAPHEIGHT) block_videoposy = 0;
  1006.     }
  1007.     
  1008.     if (stepx == 0)
  1009.     {
  1010.         // a complete column is filled up
  1011.         // : the next fill up column will be BLOCKWIDTH (16)
  1012.         // pixels at the right, so we have to adjust
  1013.         // the fillup row (for y scrolling)
  1014.         
  1015.         // step 1: blit the block which came in at
  1016.         //         the right side and which is never
  1017.         //         a fill up block
  1018.         
  1019.         mapx = mapblockx + BITMAPBLOCKSPERROW - 1;
  1020.         mapy = mapblocky;
  1021.         
  1022.         x = ROUND2BLOCKWIDTH(videoposx) + (BITMAPBLOCKSPERROW - 1) * BLOCKWIDTH;
  1023.         y = block_videoposy * BLOCKSDEPTH;
  1024.         
  1025.         DrawBlock(x,y,mapx,mapy);
  1026.         
  1027.         // step 2: blit the (new) rightmost fillup-block
  1028.         
  1029.         mapx = stepy;
  1030.         if (mapx)
  1031.         {
  1032.             // there is a fill up block;
  1033.             
  1034.             if (mapx >= TWOBLOCKSTEP)
  1035.             {
  1036.                 mapx += (TWOBLOCKSTEP - 1);
  1037.             } else {
  1038.                 mapx = mapx * 2 - 1;
  1039.             }
  1040.                         
  1041.             x = ROUND2BLOCKWIDTH(videoposx) + (mapx * BLOCKWIDTH);
  1042.             y = block_videoposy * BLOCKSDEPTH;
  1043.  
  1044.             mapx += mapblockx;
  1045.  
  1046.             DrawBlock(x,y,mapx,mapy + BITMAPBLOCKSPERCOL);
  1047.         }
  1048.     }
  1049.  
  1050.     if (stepx)
  1051.     {
  1052.         previous_xdirection = DIRECTION_RIGHT;
  1053.     } else {
  1054.         previous_xdirection = DIRECTION_IGNORE;
  1055.     }
  1056. }
  1057.  
  1058. static void CheckJoyScroll(void)
  1059. {
  1060.     WORD i,count;
  1061.     
  1062.     if (JoyFire()) count = 4; else count = 1;
  1063.  
  1064.     if (JoyUp())
  1065.     {
  1066.         for(i = 0;i < count;i++)
  1067.         {
  1068.             ScrollUp();
  1069.         }
  1070.     }
  1071.     
  1072.     if (JoyDown())
  1073.     {
  1074.         for(i = 0;i < count;i++)
  1075.         {
  1076.             ScrollDown();
  1077.         }
  1078.     }
  1079.  
  1080.     if (JoyLeft())
  1081.     {
  1082.         for(i = 0;i < count;i++)
  1083.         {
  1084.             ScrollLeft();
  1085.         }
  1086.     }
  1087.     
  1088.     if (JoyRight())
  1089.     {
  1090.         for(i = 0;i < count;i++)
  1091.         {
  1092.             ScrollRight();
  1093.         }
  1094.     }
  1095.  
  1096. }
  1097.  
  1098. static void UpdateCopperlist(void)
  1099. {
  1100.     ULONG pl;
  1101.     LONG    planeadd,planeaddx;
  1102.     WORD    i,xpos,scroll,yoffset;
  1103.     WORD    *wp;
  1104.  
  1105.     i = fetchinfo[option_fetchmode].scrollpixels;
  1106.  
  1107.     xpos = videoposx + i - 1;
  1108.  
  1109.     planeaddx = (xpos / i) * (i / 8);
  1110.     i = (i - 1) - (xpos & (i - 1));
  1111.     
  1112.     scroll = (i & 15) * 0x11;
  1113.     if (i & 16) scroll |= (0x400 + 0x4000);
  1114.     if (i & 32) scroll |= (0x800 + 0x8000);
  1115.     
  1116.     // set scroll register in BPLCON1
  1117.     
  1118.     CopBPLCON1[1] = scroll;
  1119.  
  1120.     // set top plane pointers
  1121.  
  1122.     yoffset = (videoposy + BLOCKHEIGHT) % BITMAPHEIGHT;
  1123.     planeadd = ((LONG)yoffset) * BLOCKSDEPTH * BITMAPBYTESPERROW;
  1124.     
  1125.     wp = CopPLANE1H;
  1126.  
  1127.     for(i = 0;i < BLOCKSDEPTH;i++)
  1128.     {
  1129.         pl = ((ULONG)ScreenBitmap->Planes[i]) + planeadd + planeaddx;
  1130.         
  1131.         wp[1] = (WORD)(pl >> 16);
  1132.         wp[3] = (WORD)(pl & 0xFFFF);
  1133.         
  1134.         wp += 4;
  1135.     }
  1136.  
  1137.     // set video split wait
  1138.  
  1139.     yoffset = BITMAPHEIGHT - yoffset;
  1140.     yoffset += (DIWSTART >> 8);
  1141.  
  1142.     /* CopVIDEOSPLIT must wait for line (yoffset -1 )
  1143.        CopVIDEOSPLIT2 must wait for line (yoffset)    */
  1144.  
  1145.     if (yoffset <= 255)
  1146.     {
  1147.         CopVIDEOSPLIT[0] = 0x0001;
  1148.         CopVIDEOSPLIT[2] = (yoffset - 1) * 256 + 0x1;
  1149.  
  1150.         CopVIDEOSPLIT2[0] = 0x0001;
  1151.         CopVIDEOSPLIT2[2] = yoffset * 256 + 0x1;
  1152.     } else if (yoffset == 256)
  1153.     {
  1154.         CopVIDEOSPLIT[0] = 0x0001;
  1155.         CopVIDEOSPLIT[2] = 255 * 256 + 0x1;
  1156.         
  1157.         CopVIDEOSPLIT2[0] = 0xFFDF;
  1158.         CopVIDEOSPLIT2[2] = (256 - 256) * 256 + 0x1;
  1159.     } else {
  1160.         CopVIDEOSPLIT[0] = 0xFFDF;
  1161.         CopVIDEOSPLIT[2] = (yoffset - 256 - 1) * 256 + 0x1;
  1162.         
  1163.         CopVIDEOSPLIT2[0] = 0x001;
  1164.         CopVIDEOSPLIT2[2] = (yoffset - 256) * 256 + 0x1;
  1165.     }
  1166.  
  1167.     /* Set video split plane pointers (to top of bitmap):
  1168.  
  1169.          We only set the hiwords. The lowords are automatically
  1170.          correct thanks to the modulo-trick in the copperlist
  1171.          which is setup in UpdateCopperlist().
  1172.     */
  1173.  
  1174.     pl = (ULONG)ScreenBitmap->Planes[0] +
  1175.           planeaddx;
  1176.  
  1177.     wp = CopPLANE2_1H;
  1178.     
  1179.     for(i = 0;i < BLOCKSDEPTH;i++)
  1180.     {
  1181.         wp[1] = (WORD)(pl >> 16);
  1182.  
  1183.         pl += BITMAPBYTESPERROW * BLOCKSDEPTH;
  1184.         wp += 2;
  1185.     }
  1186.  
  1187. }
  1188.  
  1189. static void MainLoop(void)
  1190. {
  1191.     if (!option_how)
  1192.     {
  1193.         // activate copperlist
  1194.         
  1195.         HardWaitBlit();
  1196.         WaitVBL();
  1197.  
  1198.         custom->copjmp2 = 0;
  1199.     }
  1200.     
  1201.     while (!LMBDown())
  1202.     {
  1203.         if (!option_how)
  1204.         {
  1205.             WaitVBeam(1);
  1206.             UpdateCopperlist();
  1207.             WaitVBeam(200);
  1208.         } else {
  1209.             Delay(1);
  1210.         }
  1211.  
  1212.         if (option_speed) *(WORD *)0xdff180 = 0xFF0;
  1213.         
  1214.         CheckJoyScroll();
  1215.  
  1216.         if (option_speed) *(WORD *)0xdff180 = 0xF00;
  1217.     }
  1218. }
  1219.  
  1220. /********************* MAIN *************************/
  1221.  
  1222. void main(void)
  1223. {
  1224.     OpenLibs();
  1225.     GetArguments();
  1226.     OpenMap();
  1227.     OpenBlocks();
  1228.     OpenDisplay();
  1229.  
  1230.     if (!option_how)
  1231.     {
  1232.         Delay(2*50);
  1233.         KillSystem();
  1234.         InitCopperlist();
  1235.     }
  1236.     FillScreen();
  1237.     
  1238.     MainLoop();
  1239.     
  1240.     if (!option_how)
  1241.     {
  1242.         ActivateSystem();
  1243.     }
  1244.  
  1245.     Cleanup(0);
  1246.     
  1247. }
  1248.  
  1249.